package com.easybbs.service.impl;

import java.io.File;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import com.easybbs.config.WebConfig;
import com.easybbs.constants.Constants;
import com.easybbs.entity.dto.FileUploadDto;
import com.easybbs.entity.dto.SysSetting4AuditDto;
import com.easybbs.entity.enums.*;
import com.easybbs.entity.po.*;
import com.easybbs.entity.query.ForumArticleAttachmentQuery;
import com.easybbs.entity.vo.request.ForumArticleLoadArticleReqVO;
import com.easybbs.entity.vo.request.ForumArticlePostArticleReqVO;
import com.easybbs.entity.vo.response.ForumArticleGetUserDownloadInfoRspVO;
import com.easybbs.entity.vo.web.ForumArticleAttachmentVo;
import com.easybbs.entity.vo.web.ForumArticleDetailVO;
import com.easybbs.entity.vo.web.ForumArticleVO;
import com.easybbs.exception.BusinessException;
import com.easybbs.mappers.UserIntegralRecordMapper;
import com.easybbs.service.*;
import com.easybbs.utils.CopyTools;
import com.easybbs.utils.SysCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.easybbs.entity.query.ForumArticleQuery;
import com.easybbs.entity.vo.PaginationResultVO;
import com.easybbs.entity.query.SimplePage;
import com.easybbs.mappers.ForumArticleMapper;
import com.easybbs.utils.StringTools;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;


/**
 * 文章信息 业务接口实现
 */
@Service("forumArticleService")
@Slf4j
public class ForumArticleServiceImpl implements ForumArticleService {

	@Resource
	private ForumArticleMapper<ForumArticle, ForumArticleQuery> forumArticleMapper;

	@Resource
	private AccountService accountService;

	@Resource
	private ForumArticleAttachmentService articleAttachmentService;

	@Resource
	private ForumArticleAttachmentDownloadService forumArticleAttachmentDownloadService;

	@Resource
	private LikeRecordService likeRecordService;

	@Resource
	private ForumCommentService forumCommentService;

	@Resource
	private UserMessageService userMessageService;

	@Resource
	private WebConfig webConfig;


	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<ForumArticle> findListByParam(ForumArticleQuery param) {
		return this.forumArticleMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(ForumArticleQuery param) {
		return this.forumArticleMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<ForumArticle> findListByPage(ForumArticleQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<ForumArticle> list = this.findListByParam(param);
		PaginationResultVO<ForumArticle> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(ForumArticle bean) {
		return this.forumArticleMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<ForumArticle> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.forumArticleMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<ForumArticle> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.forumArticleMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(ForumArticle bean, ForumArticleQuery param) {
		StringTools.checkParam(param);
		return this.forumArticleMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(ForumArticleQuery param) {
		StringTools.checkParam(param);
		return this.forumArticleMapper.deleteByParam(param);
	}

	/**
	 * 根据ArticleId获取对象
	 */
	@Override
	public ForumArticle getForumArticleByArticleId(String articleId) {
		return this.forumArticleMapper.selectByArticleId(articleId);
	}

	/**
	 * 根据ArticleId修改
	 */
	@Override
	public Integer updateForumArticleByArticleId(ForumArticle bean, String articleId) {
		return this.forumArticleMapper.updateByArticleId(bean, articleId);
	}

	/**
	 * 根据ArticleId删除
	 */
	@Override
	public Integer deleteForumArticleByArticleId(String articleId) {
		return this.forumArticleMapper.deleteByArticleId(articleId);
	}

	@Override
	public PaginationResultVO<ForumArticleVO> loadArticle(ForumArticleLoadArticleReqVO reqVO) {
		ForumArticleQuery articleQuery = new ForumArticleQuery();
		articleQuery.setBoardId(reqVO.getBoardId() == null || reqVO.getBoardId() == 0 ? null : reqVO.getBoardId());
		articleQuery.setpBoardId(reqVO.getPBoardId());
		articleQuery.setPageNo(reqVO.getPageNo());

		/**
		 * 如果用户登录，则只显示登录用户的文章，否则只显示审核通过的文章
		 */
		UserInfo loginUserInfo = accountService.getLoginOrNotUserInfo();
		if (!ObjectUtils.isEmpty(loginUserInfo)) {
			articleQuery.setUserId(loginUserInfo.getUserId());
		} else {
			articleQuery.setStatus(ArticleStatusEnum.AUDIT.getStatus());
		}

		ArticleOrderTypeEnum orderTypeEnum = ArticleOrderTypeEnum.getByType(reqVO.getOrderType());
		/**
		 * 如果没有指定排序方式，则默认按照热度排序
		 */
		orderTypeEnum = orderTypeEnum == null ? ArticleOrderTypeEnum.HOT : orderTypeEnum;
		articleQuery.setOrderBy(orderTypeEnum.getOrderSql());
		PaginationResultVO<ForumArticle> listByPage = this.findListByPage(articleQuery);
		return convert2PaginationVO(listByPage, ForumArticleVO.class);
	}

	protected <S, T> PaginationResultVO<T> convert2PaginationVO(PaginationResultVO<S> result, Class<T> classz) {
		PaginationResultVO<T> resultVO = new PaginationResultVO<>();
		resultVO.setList(CopyTools.copyList(result.getList(), classz));
		resultVO.setPageNo(result.getPageNo());
		resultVO.setPageSize(result.getPageSize());
		resultVO.setPageTotal(result.getPageTotal());
		resultVO.setTotalCount(result.getTotalCount());
		return resultVO;
	}

	@Override
	public ForumArticleDetailVO getArticleDetail(String articleId) {
		// 点击文章详情，需要进行读文章操作，增加阅读数，增加浏览记录等
		ForumArticle forumArticle = this.readArticle(articleId);


		UserInfo loginUserInfo = accountService.getLoginOrNotUserInfo();

		/**
		 * 如果文章不存在，或者文章状态为删除，或者文章状态为未审核，并且当前用户不是文章作者，则抛出异常
		 * 只有登录用户才能查看未审核的文章
		 * 管理员可以查看所有文章
		 */
		if (ObjectUtils.isEmpty(forumArticle) || forumArticle.getStatus().equals(ArticleStatusEnum.DEL.getStatus()) ||
				(ArticleStatusEnum.NO_AUDIT.getStatus().equals(forumArticle.getStatus()) && (ObjectUtils.isEmpty(loginUserInfo) || !loginUserInfo.getUserId().equals(forumArticle.getUserId())
  					&& !loginUserInfo.getRole().equals(UserRoleEnum.ADMIN.getRoleName())
				))
		) {
			throw new BusinessException(ResponseCodeEnum.CODE_404);
		}
		ForumArticleDetailVO articleDetailVO = new ForumArticleDetailVO();
		articleDetailVO.setForumArticle(CopyTools.copy(forumArticle, ForumArticleVO.class));

		// 是否有附件
		if (forumArticle.getAttachmentType().equals(ArticleAttachmentTypeEnum.HAVE_ATTACHMENT.getType())) {
			ForumArticleAttachmentQuery attachmentQuery = new ForumArticleAttachmentQuery();
			attachmentQuery.setArticleId(articleId);
			List<ForumArticleAttachment> articleAttachments = articleAttachmentService.findListByParam(attachmentQuery);
			log.info(articleAttachments.toString());
			if (!articleAttachments.isEmpty()) {
				articleDetailVO.setAttachment(CopyTools.copy(articleAttachments.get(0), ForumArticleAttachmentVo.class));
			}
		}

		// 当前登录的用户是否点赞了文章
		if (!ObjectUtils.isEmpty(loginUserInfo)) {
			String userId = loginUserInfo.getUserId();
			LikeRecord userLikeRecord = likeRecordService.getLikeRecordByObjectIdAndUserIdAndOpType(articleId, userId, OperRecordOpTypeEnum.ARTICLE_LIKE.getType());
			if (!ObjectUtils.isEmpty(userLikeRecord)) {
				articleDetailVO.setHaveLike(true);
			}
		}

		return articleDetailVO;
	}

	private ForumArticle readArticle(String articleId) {
		// 先找到文章
		ForumArticle forumArticleByArticleId = this.getForumArticleByArticleId(articleId);
		if (forumArticleByArticleId == null) {
			throw new BusinessException(ResponseCodeEnum.CODE_404);
		}
		// 只能是审核通过的文章才能阅读
		if (ArticleStatusEnum.AUDIT.getStatus().equals(forumArticleByArticleId.getStatus())) {
			this.updateArticleCount(UpdateArticleCountTypeEnum.READ_COUNT, Constants.ONE, articleId);
		}
		return forumArticleByArticleId;
	}

	public void updateArticleCount(UpdateArticleCountTypeEnum updateArticleCountTypeEnum, Integer one, String articleId) {
		forumArticleMapper.updateArticleCount(updateArticleCountTypeEnum.getType(), one, articleId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void doLike(String objectId, UserInfo userInfo, OperRecordOpTypeEnum typeEnum) {

		String userId = userInfo.getUserId();
		UserMessage userMessage = new UserMessage();
		userMessage.setCreateTime(new Date());
		switch (typeEnum) {
			case ARTICLE_LIKE:
				// 文章点赞
				ForumArticle forumArticle = forumArticleMapper.selectByArticleId(objectId);
				if (ObjectUtils.isEmpty(forumArticle)) {
					throw new BusinessException("文章不存在");
				}
				if (!forumArticle.getStatus().equals(ArticleStatusEnum.AUDIT.getStatus())) {
					throw new BusinessException("只能点赞审核通过的文章");
				}
				articleLike(objectId, forumArticle, userId, typeEnum);
				userMessage.setArticleId(objectId);
				userMessage.setArticleTitle(forumArticle.getTitle());
				userMessage.setMessageType(MessageTypeEnum.ARTICLE_LIKE.getType());
				userMessage.setCommentId(Constants.ZERO);
				userMessage.setReceivedUserId(forumArticle.getUserId());
				break;
			case COMMENT_LIKE:
				// 评论点赞
				ForumComment forumComment = forumCommentService.getForumCommentByCommentId(Integer.valueOf(objectId));
				if (ObjectUtils.isEmpty(forumComment)) {
					throw new BusinessException("评论不存在");
				}
				if (!forumComment.getStatus().equals(CommentStatusEnum.AUDIT.getStatus())) {
					throw new BusinessException("只能点赞审核通过的评论");
				}
				commentLike(objectId, forumComment, userId, typeEnum);

				forumArticle = forumArticleMapper.selectByArticleId(forumComment.getArticleId());
				userMessage.setArticleId(objectId);
				userMessage.setArticleTitle(forumArticle.getTitle());
				userMessage.setMessageType(MessageTypeEnum.ARTICLE_LIKE.getType());
				userMessage.setCommentId(forumComment.getCommentId());
				userMessage.setReceivedUserId(forumArticle.getUserId());
				userMessage.setMessageContent(forumComment.getContent());
				break;
		}
		userMessage.setSendUserId(userId);
		userMessage.setSendNickName(userInfo.getNickName());
		userMessage.setStatus(MessageStatusEnum.NO_READ.getStatus());
		if (!userId.equals(userMessage.getReceivedUserId())) {
			UserMessage dbInfo = userMessageService.getUserMessageByArticleIdAndCommentIdAndSendUserIdAndMessageType(
					userMessage.getArticleId(), userMessage.getCommentId(), userMessage.getSendUserId(),
					userMessage.getMessageType()
			);
			if (dbInfo == null) {
				userMessageService.add(userMessage);
			}
		}
	}

	public void articleLike(String objectId, ForumArticle forumArticle, String userId, OperRecordOpTypeEnum opTypeEnum) throws BusinessException {
		LikeRecord record = likeRecordService.getLikeRecordByObjectIdAndUserIdAndOpType(objectId, userId, opTypeEnum.getType());
		Integer changeCount = 0;
		if (record != null) {
			changeCount = -1;
			likeRecordService.deleteLikeRecordByObjectIdAndUserIdAndOpType(objectId, userId, opTypeEnum.getType());
		} else {
			changeCount = 1;
			LikeRecord likeRecord = new LikeRecord();
			likeRecord.setObjectId(objectId);
			likeRecord.setUserId(userId);
			likeRecord.setOpType(opTypeEnum.getType());
			likeRecord.setCreateTime(new Date());
			likeRecord.setAuthorUserId(forumArticle.getUserId());
			likeRecordService.add(likeRecord);
		}
		forumArticleMapper.updateArticleCount(UpdateArticleCountTypeEnum.GOOD_COUNT.getType(), changeCount, objectId);
	}

	public void commentLike(String objectId, ForumComment forumComment, String userId, OperRecordOpTypeEnum opTypeEnum) throws BusinessException {
		LikeRecord record = likeRecordService.getLikeRecordByObjectIdAndUserIdAndOpType(objectId, userId, opTypeEnum.getType());
		Integer changeCount = 0;
		if (record != null) {
			changeCount = -1;
			likeRecordService.deleteLikeRecordByObjectIdAndUserIdAndOpType(objectId, userId, opTypeEnum.getType());
		} else {
			changeCount = 1;
			LikeRecord likeRecord = new LikeRecord();
			likeRecord.setObjectId(objectId);
			likeRecord.setUserId(userId);
			likeRecord.setOpType(opTypeEnum.getType());
			likeRecord.setCreateTime(new Date());
			likeRecord.setAuthorUserId(forumComment.getUserId());
			likeRecordService.add(likeRecord);
		}
		forumCommentService.updateCommentGoodCount(changeCount, Integer.valueOf(objectId));
	}

	@Override
	public ForumArticleGetUserDownloadInfoRspVO getUserDownloadInfo(String fileId) {
		ForumArticleGetUserDownloadInfoRspVO rspVO = new ForumArticleGetUserDownloadInfoRspVO();
		// 拿到登录用户的信息
		UserInfo loginUserInfo = accountService.getOnlyLoginUserInfo();
		ForumArticleAttachmentDownload downloadInfo = forumArticleAttachmentDownloadService.getForumArticleAttachmentDownloadByFileIdAndUserId(fileId, loginUserInfo.getUserId());
		if (!ObjectUtils.isEmpty(downloadInfo)) {
			rspVO.setHaveDownload(true);
		}
		rspVO.setUserIntegral(loginUserInfo.getCurrentIntegral());

		return rspVO;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public String postArticle(ForumArticlePostArticleReqVO reqVO) {
		// 发布文章，如果有附件，需要另外保存附件
		Integer editorType = reqVO.getEditorType();

		EditorTypeEnum editorTypeEnum = EditorTypeEnum.geByType(editorType);
		if (ObjectUtils.isEmpty(editorTypeEnum)) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		if (editorTypeEnum.equals(EditorTypeEnum.MARKDOWN) && StringTools.isEmpty(reqVO.getMarkdownContent())) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		String title = StringTools.eecpapeHtml(reqVO.getTitle());
		ForumArticle forumArticle = new ForumArticle();
		forumArticle.setpBoardId(reqVO.getPBoardId());
		forumArticle.setBoardId(reqVO.getBoardId());
		forumArticle.setTitle(title);
		forumArticle.setSummary(reqVO.getSummary());
		forumArticle.setContent(reqVO.getContent());
		forumArticle.setMarkdownContent(reqVO.getMarkdownContent());
		forumArticle.setEditorType(editorType);

		UserInfo loginUserInfo = accountService.getOnlyLoginUserInfo();

		forumArticle.setUserId(loginUserInfo.getUserId());
		forumArticle.setNickName(loginUserInfo.getNickName());
		forumArticle.setUserIpAddress(loginUserInfo.getLastLoginIpAddress());

		// 附件信息
		ForumArticleAttachment forumArticleAttachment = new ForumArticleAttachment();
		forumArticleAttachment.setIntegral(reqVO.getIntegral() == null ? 0 : reqVO.getIntegral());
		String articleId = articleAttachmentService.postArticle(loginUserInfo.getRole().equals(UserRoleEnum.ADMIN.getRoleName()), forumArticle, forumArticleAttachment, reqVO.getCover(), reqVO.getAttachment());

		return articleId;
	}

	@Override
	public ForumArticleDetailVO getArticleDetail4Update(String articleId) {
		ForumArticle forumArticle = this.getForumArticleByArticleId(articleId);
		UserInfo loginUserInfo = accountService.getOnlyLoginUserInfo();
		if (forumArticle == null || !forumArticle.getUserId().equals(loginUserInfo.getUserId())) {
			throw new BusinessException("文章不存在或无权编辑该文章");
		}
		ForumArticleDetailVO detailVO = new ForumArticleDetailVO();
		detailVO.setForumArticle(CopyTools.copy(forumArticle, ForumArticleVO.class));
		if (forumArticle.getAttachmentType() == Constants.ONE) {
			ForumArticleAttachmentQuery articleAttachmentQuery = new ForumArticleAttachmentQuery();
			articleAttachmentQuery.setArticleId(articleId);
			List<ForumArticleAttachment> forumArticleAttachmentList = articleAttachmentService.findListByParam(articleAttachmentQuery);
			if (!forumArticleAttachmentList.isEmpty()) {
				detailVO.setAttachment(CopyTools.copy(forumArticleAttachmentList.get(0), ForumArticleAttachmentVo.class));
			}
		}
		return detailVO;
	}

	@Override
	public PaginationResultVO<ForumArticle> search(String keyword) {
		ForumArticleQuery query = new ForumArticleQuery();
		query.setTitleFuzzy(keyword);
		query.setOrderBy("post_time desc");
		PaginationResultVO<ForumArticle> listByPage = this.findListByPage(query);
		// TODO: 整合ES

		return listByPage;
	}
}